home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / calc < prev    next >
Encoding:
Internet Message Format  |  1988-05-17  |  23.6 KB

  1. Subject:  v14i098:  A trig/multi-base calculator
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Wayne Mesard <mesard@bbn.com>
  7. Posting-number: Volume 14, Issue 98
  8. Archive-name: calc
  9.  
  10. [   This program evalues mathematical expressions, like
  11.         calc '2 * 3 / sin 45'
  12.     it works off the command line, or standard input.
  13.     Yeah, you could consider this redundant given dc and bc, but
  14.     I find this easier to use than either one of them.
  15.     Porters beware of the machine.h / mch_defines stuff.  --r$  ]
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of shell archive."
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'Makefile'\"
  27. else
  28. echo shar: Extracting \"'Makefile'\" \(195 characters\)
  29. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  30. BIN = ../bin/
  31. CFLAGS = -O
  32. X
  33. calc: $(BIN)calc
  34. X
  35. X$(BIN)calc: calc.c machine.h
  36. X    $(CC) calc.c -lm -o $(BIN)calc
  37. X
  38. machine.h:
  39. X    $(CC) mch_defines.c -o mch_defines
  40. X    mch_defines > machine.h
  41. X    rm mch_defines
  42. END_OF_FILE
  43. if test 195 -ne `wc -c <'Makefile'`; then
  44.     echo shar: \"'Makefile'\" unpacked with wrong size!
  45. fi
  46. # end of 'Makefile'
  47. fi
  48. if test -f 'POSTME' -a "${1}" != "-c" ; then 
  49.   echo shar: Will not clobber existing file \"'POSTME'\"
  50. else
  51. echo shar: Extracting \"'POSTME'\" \(0 characters\)
  52. sed "s/^X//" >'POSTME' <<'END_OF_FILE'
  53. END_OF_FILE
  54. if test 0 -ne `wc -c <'POSTME'`; then
  55.     echo shar: \"'POSTME'\" unpacked with wrong size!
  56. fi
  57. # end of 'POSTME'
  58. fi
  59. if test -f 'calc.c' -a "${1}" != "-c" ; then 
  60.   echo shar: Will not clobber existing file \"'calc.c'\"
  61. else
  62. echo shar: Extracting \"'calc.c'\" \(11315 characters\)
  63. sed "s/^X//" >'calc.c' <<'END_OF_FILE'
  64. X/**************************************************************************
  65. X *      calc: a command-line calculator program                           *
  66. X *      Copyright (c) 1988 Wayne Mesard                                   *
  67. X *                                                                        *
  68. X *      This is free software.  It may be reproduced, retransmitted,      *
  69. X *      redistributed and otherwise propogated at will, provided that     *
  70. X *      this notice remains intact and in place.                          *
  71. X *                                                                        *
  72. X *      Please direct bug reports, code enhancements and comments         *
  73. X *      to mesard@BBN.COM.                                                *
  74. X *                                                                        *
  75. X **************************************************************************/
  76. X
  77. X
  78. X#include <stdio.h>
  79. X#include <ctype.h>
  80. X#include <strings.h>
  81. X#include <math.h>
  82. X#include <setjmp.h>
  83. X
  84. X#define PIdiv180 0.017453292519943295
  85. X#define PI       3.14159265358979323846
  86. X#include "machine.h"
  87. X#ifdef Mch_Lsz
  88. X#  define TwoToTheNLessOne   (unsigned long)(1<<(Mch_Lsz-1))
  89. X#else    /* Assume 16 bits */
  90. X#  define TwoToTheNLessOne    32768
  91. X#endif
  92. X
  93. X#define MAXLINE 512
  94. X
  95. X#define OP "{(["
  96. X#define CP "})]"
  97. X#define SYMBOLS "{([+-/xX*%:&^|<>~gnpst" /* Used to distinguish unary from
  98. X                    binary minus.  Letters at end of 
  99. X                    string are ends of function names. */
  100. X
  101. X#define SYMBOL_LOWERS "xabcdef"     /* Used to detect implied multiplication.
  102. X                     * Identifies these as symbols and not
  103. X                     * part of a function name.
  104. X                     */
  105. X
  106. X#define DECFMT "\t% .16g\n"
  107. X#define BINFMT "\tb%*s\n"
  108. X#define FLTFMT "\t% .*f\n"
  109. X#define HEXFMT "\th%lX\n"
  110. X#define OCTFMT "\to%lo\n"
  111. X#define ASCFMT "\t@%c\n"
  112. X
  113. jmp_buf err_recover;
  114. int abort_on_err = 0;
  115. double answer = 0.0;
  116. X
  117. main(argc, argv)       /* calc: a desk-top calculator */
  118. int argc;
  119. char *argv[];
  120. X{
  121. X    char    s[MAXLINE];
  122. X    int     precision = -1;
  123. X    char    mode = '\0';
  124. X    int     getwhitlessline(), isatty();
  125. X    int        keepchecking = 1;
  126. X
  127. X    for (argv++, argc--; argc && **argv == '-' && keepchecking; argv++, argc--)
  128. X    switch ((*argv)[1]) {
  129. X        case 'p':
  130. X        if (isdigit((*argv)[2]))
  131. X            precision = atoi( &(*argv)[2]);
  132. X        else {
  133. X            abort_on_err = 1;
  134. X            error("bad argument to -p option");
  135. X        }
  136. X        break;
  137. X        case 'e':
  138. X        abort_on_err = 1;
  139. X        break;
  140. X        case 'd':
  141. X        case 'h': 
  142. X        case 'o': 
  143. X        case 'b':
  144. X        case '@':
  145. X        mode = (*argv)[1];
  146. X        break;
  147. X        case '\0':
  148. X        keepchecking = 0;
  149. X        break;
  150. X        default:    /* Oops, this must be a unary minus, not an option. */
  151. X        keepchecking = 0;
  152. X        argv--;
  153. X        argc++;
  154. X        break;
  155. X    }
  156. X
  157. X    if (argc) {
  158. X    s[0] = '\0';
  159. X    while (argc-- > 0)
  160. X        strcat (s, *argv++);
  161. X    abort_on_err = 1;
  162. X    Compute (mode, s, precision);
  163. X    }
  164. X    else {
  165. X    if (isatty(0))
  166. X        printf ("Enter equations.  Blank line to terminate.\n");
  167. X    setjmp(err_recover);
  168. X    while (getwhitlessline (s))
  169. X        Compute (mode, s, precision);
  170. X    }
  171. X}
  172. X
  173. X
  174. Compute(mode, s, precision)
  175. char mode, *s;
  176. int precision;
  177. X{
  178. X    double calc();
  179. X    char    *ftob(), binnum[MAXLINE];
  180. X
  181. X    answer = calc(s);
  182. X    switch(mode) {
  183. X    case '\0':
  184. X    case 'd':
  185. X        if (precision >= 0)
  186. X        printf(FLTFMT, precision, answer);
  187. X        else
  188. X        printf(DECFMT, answer);
  189. X        break;
  190. X    case 'h':
  191. X        printf(HEXFMT, (unsigned long) answer);
  192. X        break;
  193. X    case 'o':
  194. X        printf(OCTFMT, (unsigned long) answer);
  195. X        break;
  196. X    case 'b':
  197. X        printf(BINFMT, (precision > 0 ? precision : 0),
  198. X                   ftob(binnum, answer));
  199. X        break;
  200. X    case '@':
  201. X        printf(ASCFMT, (char) answer);
  202. X        break;
  203. X    }
  204. X}
  205. X
  206. X
  207. X
  208. X/*******
  209. X *  When debugging uncomment this proc and change the following proc's name
  210. X *  to calc2
  211. X *
  212. double calc(e)
  213. char *e;
  214. X{
  215. X    double calc2();
  216. X    double val;
  217. X
  218. X    printf("calling with **%s**\n", e);
  219. X    val = calc2(e);
  220. X    printf("returning **%f**\n", val);
  221. X    return(val);
  222. X}
  223. X*******/
  224. X
  225. X
  226. X/* Recursively, parse an equation string.
  227. X * This is hideously inefficient, since findop() is called on each invokation.
  228. X * O(n) would be possible if findop() where modified to walk through the string
  229. X * once and build a priority queue for evaluation of operators.
  230. X *    But hey, the kids love it, and I know for a fact that my Data Structures
  231. X * prof never wrote a linear algorithm in his life:-)
  232. X */
  233. X
  234. double calc(eqn)
  235. char *eqn;
  236. X{
  237. X    double  vleft, temp;
  238. X    long    tempi;
  239. X    char    left[MAXLINE], eqncp[MAXLINE];
  240. X    char   *findop (), *opptr;
  241. X    double  btof();
  242. X
  243. X    while (*eqn == ' ' || *eqn == '\t')
  244. X    eqn++;
  245. X
  246. X    if (!*eqn)
  247. X    error("missing expression");
  248. X
  249. X    else if (opptr = findop(eqn)) {
  250. X    strncpy (left, eqn, opptr - eqn);
  251. X    left[opptr - eqn] = '\0';
  252. X    vleft = calc(left);
  253. X    switch (*opptr) {
  254. X        case '+': 
  255. X        return(vleft + calc(++opptr));
  256. X        case '-': 
  257. X        return(vleft - calc(++opptr));
  258. X        case '/': 
  259. X        if ((temp = calc(++opptr)) == 0.0)
  260. X            error ("division by zero");
  261. X        else
  262. X            return(vleft / temp);
  263. X        case 'x': 
  264. X        case 'X': 
  265. X        case '*': 
  266. X        return(vleft * calc(++opptr));
  267. X        case '%': 
  268. X        if ((temp = fabs(floor (calc(++opptr)+0.5))) == 0.0 ||
  269. X                temp > (TwoToTheNLessOne-1))
  270. X            error("bad argument to modulo");
  271. X        return((double)((long) (floor (vleft) + 0.5) %
  272. X                        (long) temp));
  273. X        case ':': 
  274. X        return(pow(vleft, calc(++opptr)));
  275. X        case '&': 
  276. X        return((double)((unsigned long)vleft &
  277. X                (unsigned long)calc(++opptr)));
  278. X        case '^': 
  279. X        return((double)((unsigned long)vleft ^
  280. X                (unsigned long)calc(++opptr)));
  281. X        case '|': 
  282. X        return((double)((unsigned long)vleft |
  283. X                (unsigned long)calc(++opptr)));
  284. X        case '<': 
  285. X        return((double)((unsigned long)vleft <<
  286. X                (unsigned long)calc(++opptr)));
  287. X        case '>': 
  288. X        return((double)((unsigned long)vleft >>
  289. X                (unsigned long)calc(++opptr)));
  290. X
  291. X        default: /* implied multiplication */
  292. X        return(vleft * calc(opptr));
  293. X        }
  294. X    }
  295. X
  296. X    else if (index (OP, *eqn)) {
  297. X        strcpy(eqncp, ++eqn);
  298. X        eqncp[strlen (eqncp) - 1] = '\0';
  299. X        return(calc (eqncp));
  300. X    }
  301. X
  302. X    else if (*eqn == '+')
  303. X        return(calc(eqn+1));
  304. X    else if (*eqn == '-')
  305. X        return(-1.0 * calc(eqn+1));
  306. X        else if (*eqn == '~')
  307. X        return((double)(~ (unsigned long)calc(eqn+1)));
  308. X
  309. X    else if (strncmp(eqn, "sin", 3) == 0)
  310. X        return(sin (calc(eqn+3) * PIdiv180));
  311. X    else if (strncmp(eqn, "cos", 3) == 0)
  312. X        return(cos (calc(eqn+3) * PIdiv180));
  313. X    else if (strncmp(eqn, "tan", 3) == 0)
  314. X        return(tan (calc(eqn+3) * PIdiv180));
  315. X    else if (strncmp(eqn, "atan", 4) == 0)
  316. X        return(atan (calc(eqn+4)) / PIdiv180);
  317. X
  318. X    else if (strncmp(eqn, "sqrt", 4) == 0)
  319. X        return(sqrt (calc(eqn+4)));
  320. X    else if (strncmp(eqn, "log", 3) == 0)
  321. X        return(log10 (calc(eqn+3)));
  322. X    else if (strncmp(eqn, "ln", 2) == 0)
  323. X        return(log (calc(eqn+2)));
  324. X    else if (strncmp(eqn, "exp", 3) == 0)
  325. X        return(exp (calc(eqn+3)));
  326. X    else if (strncmp(eqn, "pi", 2) == 0 || strncmp(eqn, "PI", 2) == 0)
  327. X        return(PI);
  328. X    else if (strncmp(eqn, "prev", 4) == 0)
  329. X        return(answer);
  330. X
  331. X    else if (*eqn == 'h') {
  332. X        sscanf(eqn+1, "%lx", &tempi);
  333. X        return((double) tempi);
  334. X    }
  335. X    else if (*eqn == 'o') {
  336. X        sscanf(eqn+1, "%lo", &tempi);
  337. X        return((double) tempi);
  338. X    }
  339. X    else if (*eqn == 'b')
  340. X        return(btof(eqn+1));
  341. X        else if (*eqn == '@')
  342. X        return((double) *(eqn+1));
  343. X    else if (!(isdigit(*eqn) || *eqn == '.') )
  344. X        error("illegal expression");
  345. X    else
  346. X        return(atof (eqn));
  347. X}
  348. X
  349. X
  350. X
  351. X/*
  352. X * Takes a parenthesized expression and returns a pointer to the closing paren.
  353. X */
  354. X
  355. char *findclose(s)
  356. char *s;
  357. X{
  358. X    register int lev = 0;
  359. X
  360. X    for (; *s && !(lev==1 && index(CP, *s)); s++)
  361. X    if (index(OP, *s))
  362. X        lev++;
  363. X    else if (index(CP, *s))
  364. X        lev--;
  365. X
  366. X    if (!*s)
  367. X    error("unmatched open paren");
  368. X    else
  369. X    return(s);
  370. X}
  371. X
  372. X
  373. X/** Precedence levels for binary operators **/
  374. X
  375. X#define OPTYPE int
  376. X#define NONOP  0
  377. X#define NULLOP 1
  378. X#define EXP    3
  379. X#define MULT   5
  380. X#define DIV    5
  381. X#define MOD    6
  382. X#define ADD    7
  383. X#define SUBTR  7
  384. X#define LSHIFT 8
  385. X#define RSHIFT 8
  386. X#define BAND   9
  387. X#define BXOR   10
  388. X#define BOR    11
  389. X
  390. char *findop(s)
  391. char *s;
  392. X{
  393. X    register OPTYPE op;
  394. X    OPTYPE bestop = NULLOP;
  395. X    char *bestptr = 0;
  396. X    register char last = '\0';
  397. X
  398. X    while (*s) {
  399. X    op = NONOP;
  400. X    if (*s == ' ' || *s == '\t') { /* Don't let lasts get assigned to space */
  401. X        s++;
  402. X        continue;
  403. X    }
  404. X    else {
  405. X        switch (*s) {
  406. X        case ':': 
  407. X            op = EXP;
  408. X            break;
  409. X        case '%':
  410. X            op = MOD;
  411. X            break;
  412. X        case 'x': 
  413. X        case 'X': 
  414. X        case '*': 
  415. X            if (!(*s=='x' && last=='e' && *(s+1)=='p')) /* exp() function */
  416. X            op = MULT;
  417. X            break;
  418. X        case '/': 
  419. X            op = DIV;
  420. X            break;
  421. X        case '+': 
  422. X            /* "+" means unary plus (not add) if it follows a
  423. X             * symbol or a function name.
  424. X             */
  425. X            if (!index(SYMBOLS, last))
  426. X            op = ADD;
  427. X            break;
  428. X        case '-': 
  429. X            /* "-" means unary minus (not subtract) if it follows a
  430. X             * symbol or a function name.
  431. X             */
  432. X            if (!index(SYMBOLS, last))
  433. X            op = SUBTR;
  434. X            break;
  435. X        case '<':
  436. X            op = LSHIFT;
  437. X            break;
  438. X        case '>':
  439. X            op = RSHIFT;
  440. X            break;
  441. X        case '&':
  442. X            op = BAND;
  443. X            break;
  444. X        case '^':
  445. X            op = BXOR;
  446. X            break;
  447. X        case '|':
  448. X            op = BOR;
  449. X            break;
  450. X        default:
  451. X            /* Implied multiplication occurs when a digit or a
  452. X             * close paren is followed by a func-call, or an open
  453. X             * paren.  The check for "co" and "at" is to distinguish
  454. X             * 'c' and 'a' as hex digits and their appearance in
  455. X             * "cos" and "atan".
  456. X             */
  457. X            if ((last && (isdigit(last) || index(CP, last))) && 
  458. X                ((islower(*s)  || index(OP, *s)) ||
  459. X             (!isdigit(last) && isdigit(*s))) &&
  460. X            (!index(SYMBOL_LOWERS, *s) ||
  461. X             !strncmp("co", s, 2) || !strncmp("at", s, 2)))
  462. X                op = MULT;
  463. X        }
  464. X
  465. X        if (op >= bestop) {
  466. X        bestop = op;
  467. X        bestptr = s;
  468. X        }
  469. X    }
  470. X
  471. X    if (index(OP, *s))
  472. X        s = findclose(s);
  473. X
  474. X    last = *s++;
  475. X    }
  476. X    return(bestptr);
  477. X}
  478. X
  479. X
  480. X
  481. X/*
  482. X * Places a binary representation of "val" in the string "s" and returns
  483. X * a pointer to the start of that string.  "val" should be (or will be coerced
  484. X * to )an integer between +/- 2^n, where n is the number of bits in a long int.
  485. X */
  486. X
  487. char *ftob(s, val)
  488. char *s;
  489. double val;
  490. X{
  491. X    unsigned long lval = (val<0.0 ? -val : val);
  492. X    unsigned long i;
  493. X    char *s0 = s;
  494. X
  495. X    if (lval == 0)
  496. X    *s++ = '0';
  497. X    else 
  498. X    for (i = TwoToTheNLessOne; i; i>>=1)
  499. X        if (lval & i)
  500. X        *s++ = '1';
  501. X        else {
  502. X        *s = '0';
  503. X        if (s != s0)
  504. X            s++;
  505. X        }
  506. X
  507. X    *s = '\0';
  508. X    return(s0);
  509. X}
  510. X
  511. X
  512. X
  513. X/*
  514. X * Takes a string containing a binary number and returns its 
  515. X * decimal equivelant.
  516. X */
  517. X
  518. double btof(s)
  519. char *s;
  520. X{
  521. X    unsigned long i, val = 0;
  522. X
  523. X    for (i = (unsigned long)1<<(strlen(s)-1); i; i>>=1, s++)
  524. X    if (*s == '1')
  525. X        val |= i;
  526. X    else if (*s != '0')
  527. X        error("bad binary digit");
  528. X
  529. X
  530. X    return((double) val);
  531. X}
  532. X
  533. X
  534. X
  535. X
  536. X/*
  537. X * Reads a line from the stdin, and puts it in s after striping
  538. X * off all spaces and tabs.
  539. X * Returns the length of s.
  540. X */
  541. X
  542. int getwhitlessline(s)
  543. char *s;
  544. X{
  545. X    register int i, c;
  546. X
  547. X    for(i = 0; i <= MAXLINE && ((c=getchar()) != '\n') && c!=EOF; i+=(c!=' ' && c!='\t'))
  548. X    s[i] = c;
  549. X    s[i] = '\0';
  550. X    return(i);
  551. X}
  552. X
  553. X
  554. X
  555. X/*
  556. X * Displays an error message and exits unless a jmp_buf has been
  557. X * set to return to in just such emergencies.  (Capt. Kirk always
  558. X * defined a jmp_buf.)
  559. X */
  560. X
  561. error(msg)
  562. char *msg;
  563. X{
  564. X    printf("calc: error--%s\n", msg);
  565. X    if (abort_on_err)
  566. X    exit(1);
  567. X    else
  568. X    longjmp(err_recover, 0);
  569. X}
  570. X
  571. END_OF_FILE
  572. if test 11315 -ne `wc -c <'calc.c'`; then
  573.     echo shar: \"'calc.c'\" unpacked with wrong size!
  574. fi
  575. # end of 'calc.c'
  576. fi
  577. if test -f 'calc.man' -a "${1}" != "-c" ; then 
  578.   echo shar: Will not clobber existing file \"'calc.man'\"
  579. else
  580. echo shar: Extracting \"'calc.man'\" \(5961 characters\)
  581. sed "s/^X//" >'calc.man' <<'END_OF_FILE'
  582. X.TH CALC 1L "24 February 1988" " " " "
  583. X
  584. X.de AI   \"Init annotation environment.
  585. X.PD 0
  586. X.nf
  587. X.na
  588. X.ta .5i
  589. X..
  590. X.de AU    \"Uninit annotation environment.
  591. X.PD
  592. X.fi
  593. X.ad
  594. X..
  595. X.de BA    \"Begin annotation
  596. X.fi
  597. X.IP "\\$1" 25
  598. X..
  599. X.de EA    \"End annotation
  600. X.nf
  601. X.PP
  602. X..
  603. X
  604. X.SH NAME
  605. calc \- a command line calculator
  606. X
  607. X.SH SYNOPSIS
  608. X.B calc
  609. X[ 
  610. X.B \-d \-h \-o \-b \-@ 
  611. X.BI \-p n 
  612. X.B
  613. X\-e \- 
  614. X] 
  615. X[
  616. X.I expression 
  617. X]
  618. X
  619. X.SH DESCRIPTION
  620. X.I calc 
  621. evaluates mathematical expressions.
  622. X
  623. An expression is any decimal number in integer or real format.  It may
  624. also be a binary, octal or hexidecimal integer prefixed by,
  625. respectively,
  626. X.I b, 
  627. X.I o, 
  628. or 
  629. X.I h, 
  630. or an ASCII character, prefixed by 
  631. X.I @.
  632. X
  633. An expression is also any expression preceded by one of
  634. the following:
  635. X
  636. X.nf
  637. X.ta 1i 2i 3i
  638. X    sin    log    - (unary minus)
  639. X    cos    ln    + (unary plus)
  640. X    tan    sqrt    ~ (one's complement)
  641. X    atan    exp
  642. X.fi
  643. X
  644. or any two expressions separated by one of the following operators:
  645. X
  646. X.nf
  647. X.ta 2i +.5i +.5i
  648. X.RS 1i
  649. Exponentiation:    :
  650. Multiplication:    *    x    X
  651. X    (none: implied multiplication)
  652. Division:    /
  653. Modulo:    %
  654. Addition:    +
  655. Subtraction:    -
  656. Left shift:    <
  657. Right shift:    >
  658. Bitwise AND:    &
  659. Bitwise XOR:    ^
  660. BitWise OR:    |
  661. X.RE
  662. X.fi
  663. X
  664. An expression is any expression preceded by an opening delimeter:
  665. X
  666. X.nf
  667. X.ta 1i +.5i +.5i
  668. X    {    [    (
  669. X.fi
  670. X
  671. and followed by a closing delimeter:
  672. X
  673. X
  674. X.nf
  675. X.ta 1i +.5i +.5i
  676. X    }    ]    )
  677. X.fi
  678. X
  679. The special symbols "pi" and "PI" are also valid expressions.  So is
  680. X"prev" which returns the value of the previous equation
  681. X(multiple-expression mode only).
  682. X
  683. If the expression is omitted from the command line, then the
  684. program will be in multiple-expression mode and repeatedly read
  685. expressions from the standard input until it encounters an empty
  686. line or an end of file.
  687. X
  688. X.SH OPTIONS
  689. X.IP\fB\-d\fP
  690. X(The default mode.)  The answer is printed as a decimal
  691. number, or in scientific format if it is very large.
  692. X.IP\fB\-o\fP
  693. The answer is printed in octal, rounded down to the
  694. nearest integer.
  695. X.IP\fB\-h\fP
  696. The answer is printed in hexadecimal, rounded down to the
  697. nearest integer.
  698. X.IP\fB\-b\fP
  699. The answer is printed in binary, rounded down to the
  700. nearest integer.
  701. X.IP\fB\-@\fP
  702. The answer is printed as an ASCII character (modulo 128).
  703. X.IP\fB\-p\fP\fIn\fP
  704. Only meaningful in decimal and binary mode.  Specifies the
  705. precision (the number of digits appearing after the decimal point)
  706. for a decimal number, or the number of minimum number of digits
  707. appearing in a binary number.  (In order to line up the columns when
  708. multiple calculations are being performed.)  There
  709. must not be a space between the ``\fBp\fP'' and 
  710. X.I n.
  711. X.IP\fB\-e\fP
  712. Will cause
  713. X.I calc 
  714. to exit when a bad expression is entered.  This is only
  715. meaningful in multiple-expression mode.
  716. X.IP\fB\-\fP
  717. Indicates the end of the argument list.  This is used
  718. when the beginning of the expression might accidently be
  719. interpreted as an option.  (See EXAMPLES below.)
  720. X
  721. X.SH USAGE NOTES
  722. Arguments to trig functions are specified in degrees.
  723. X
  724. All binary operators group left-to-right, unary operators and functions
  725. group right-to-left.  Priority of functions and operators is almost
  726. identical to that of C (except modulo is slightly lower here):
  727. X
  728. X.RS .5i
  729. X.nf
  730. X.ta 1.5i +1.75i
  731. Highest:    Unary Op's    Functions
  732. X    Exponentiation
  733. X    Multiplication    Division
  734. X    Modulo
  735. X    Addition    Subtraction
  736. X    Left shift    Right shift
  737. X    And
  738. X    Xor
  739. Lowest:    Or
  740. X.fi
  741. X.RE
  742. X
  743. The C shell use many of
  744. X.IRcalc 's 
  745. symbols for its own evil purposes.  These include all three
  746. pairs of delimeters, and the asterisk.  Whenever
  747. you need a delimeter, you are advised to enclose the entire
  748. expression in double quotes to keep the shell from messing with
  749. it.  Alternatively, you can omit the expression from the command
  750. line, and have 
  751. X.I calc 
  752. prompt you for it, in which case the shell
  753. will never see what is typed.
  754. X
  755. Computations are performed using double precision floating point numbers
  756. with the following exceptions: The modulo operation (%) rounds its
  757. arguments to the nearest integer.  Bitwise and bit shift operations
  758. expect (or will truncate to) positive integers.  Hex and octal modes
  759. expect (or will truncate to) the nearest integer.
  760. When an integer is expected, it must be less than the
  761. largest long integer allowed on the machine (typically,
  762. X.if t 2\u\s-231\s0\d).  
  763. X.if n 2:31).  
  764. You will get undefined results if you go sticking large
  765. numbers where they don't belong.
  766. X
  767. X.SH EXAMPLES
  768. X.AI
  769. calc  2 + 5 x 6
  770. X     32
  771. X
  772. X.BA "calc '(2 + 5) x 6'"
  773. Parens quoted to hide them from the shell.
  774. X.EA
  775. X     42
  776. X
  777. calc -p2 "atan(tan(45))"
  778. X     45.00
  779. X
  780. calc -h  20
  781. X    h14
  782. X
  783. calc -o @A
  784. X    o101
  785. X
  786. X.BA "calc -b  2:8 + 3"
  787. Exponentiation takes precidence over addition.
  788. X.EA
  789. X    b100000011
  790. X
  791. calc  b101 - hc
  792. X    -7
  793. X
  794. X.BA "calc  -  -h4ff"
  795. X``\fB-\fP'' used so ``\fB-h\fP'' won't be interpreted as an option
  796. X.EA
  797. X    -1279
  798. X.AU
  799. X
  800. X.SH DIAGNOSTICS
  801. X.I calc 
  802. prints its error messages on the 
  803. X.B standard output.  
  804. Normally, when an error occurs 
  805. X.I calc 
  806. terminates with an exit status of 1.  The exception is when in
  807. multiple-expression mode if the 
  808. X.I e 
  809. option has
  810. X.B not 
  811. been specified.  In this case, 
  812. X.I calc 
  813. will simply report the error and move on to the next input.
  814. X
  815. The error messages are:
  816. X.RS .5i
  817. X.na
  818. X.IP "bad argument to -p option"
  819. Option must be followed by an integer argument with no
  820. intervening spaces.
  821. X.IP "missing expression"
  822. An operator of function expected an expression and didn't find one.
  823. X.IP "division by zero"
  824. Right-hand expression to the division operator evaluated to zero.
  825. X.IP "bad argument to modulo"
  826. Right-hand expression to the modulo operator was zero, or was
  827. greater than or equal to 
  828. X.if t 2\u\s-231\s0\d.
  829. X.if n 2:31.
  830. X.IP "illegal expression"
  831. An expression couldn't be parsed.
  832. X.IP "unmatched open paren"
  833. A parenthesized expression was opened, but never closed.
  834. X.IP "bad binary digit"
  835. An expression preceded by a ``\fBb\fP'' contained a character
  836. other than ``1'' and ''0''.
  837. X.ad
  838. X.RE
  839. X
  840. X.SH BUGS
  841. Ascii format (-@, and @) doesn't do anything to pretty up control
  842. characters.  For example, "calc -@ 12" may have a disconcerting result.
  843. X
  844. X
  845. X.SH AUTHOR
  846. Wayne Mesard, MESARD@BBN.COM
  847. END_OF_FILE
  848. if test 5961 -ne `wc -c <'calc.man'`; then
  849.     echo shar: \"'calc.man'\" unpacked with wrong size!
  850. fi
  851. # end of 'calc.man'
  852. fi
  853. if test -f 'machine.h' -a "${1}" != "-c" ; then 
  854.   echo shar: Will not clobber existing file \"'machine.h'\"
  855. else
  856. echo shar: Extracting \"'machine.h'\" \(110 characters\)
  857. sed "s/^X//" >'machine.h' <<'END_OF_FILE'
  858. X#define Mch_Csz 8
  859. X#define Mch_Ssz 16
  860. X#define Mch_Isz 32
  861. X#define Mch_Lsz 32
  862. X#define Mch_BE 1
  863. X#define Mch_sgc 1
  864. END_OF_FILE
  865. if test 110 -ne `wc -c <'machine.h'`; then
  866.     echo shar: \"'machine.h'\" unpacked with wrong size!
  867. fi
  868. # end of 'machine.h'
  869. fi
  870. if test -f 'mch_defines.c' -a "${1}" != "-c" ; then 
  871.   echo shar: Will not clobber existing file \"'mch_defines.c'\"
  872. else
  873. echo shar: Extracting \"'mch_defines.c'\" \(2812 characters\)
  874. sed "s/^X//" >'mch_defines.c' <<'END_OF_FILE'
  875. X/* This program was snagged off the USENET comp.lang.c mailing list 22 July 1987 */
  876. X
  877. X/* The contents of the following program are copyright 1987 by John Cowan.
  878. It is hereby released to the public domain.
  879. X
  880. This program emits C #define statements to the standard output describing
  881. the machine it is executing on.  The following #defines are generated:
  882. X        Mch_Csz -       size of a char, in bits
  883. X        Mch_Ssz -       size of a short int, in bits
  884. X        Mch_Isz -       size of a plain int, in bits
  885. X        Mch_Lsz -       size of a long int, in bits
  886. X        Mch_BE -        defined if the machine is big-endian; that is, if
  887. X                        the most significant byte in a number appears first.
  888. X        Mch_LE -        defined if the machine is little-endian; that is, if
  889. X                        the least significant byte in a number appears first.
  890. X        Mch_PDP -       defined if the machine uses PDP-11 byte ordering;
  891. X                        LE for bytes-in-a-word and BE for words-in-a-long.
  892. X        Mch_ONE -       defined if the machine uses one's complement arithmetic.
  893. X        Mch_sgc -       defined if characters can be signed.
  894. X*/
  895. X
  896. X#include <stdio.h>
  897. X
  898. char bittest[9] = "\001\001\001\001\001\001\001\001"; /*Changed from [6] for CRAY X-MP -WM*/
  899. char endtest[6] = "\001\002\003\004\005";
  900. long be = 1;
  901. long le = 1;
  902. long pdp;
  903. int byteoff;
  904. int bytesize;
  905. long longval;
  906. X
  907. main()
  908. X        {
  909. X        int i;
  910. X
  911. X        byteoff = (*(int *) bittest & 2047) - 1;
  912. X        switch (byteoff) {
  913. X        case 256: bytesize = 8; break;
  914. X        case 512: bytesize = 9; break;
  915. X        case 1024: bytesize = 10; break;
  916. X        default: fprintf(stderr, "mch: bogus byte size\n"); exit(1);
  917. X                }
  918. X        printf("#define Mch_Csz %d\n", bytesize);
  919. X        printf("#define Mch_Ssz %d\n", sizeof(short) * bytesize);
  920. X        printf("#define Mch_Isz %d\n", sizeof(int) * bytesize);
  921. X        printf("#define Mch_Lsz %d\n", sizeof(long) * bytesize);
  922. X        longval = *(long *) endtest;
  923. X        for (i = 0; i < sizeof(long); i++) {
  924. X                be *= byteoff;
  925. X                be += endtest[i];
  926. X                }
  927. X        for (i = sizeof(long) - 1; i >= 0; i--) {
  928. X                le *= byteoff;
  929. X                le += endtest[i];
  930. X                }
  931. X        pdp = 0x02010403;
  932. X        if (longval == be)
  933. X                printf("#define Mch_BE 1\n");
  934. X        else if (longval == le)
  935. X                printf("#define Mch_LE 1\n");
  936. X        else if (longval == pdp)
  937. X                printf("#define Mch_PDP 1\n");
  938. X        else {
  939. X                fprintf(stderr, "mch: bogus endianism\n");
  940. X                exit(1);
  941. X                }
  942. X        if (~0 == 0)
  943. X                printf("#define Mch_ONE 1\n");
  944. X        if ('\377' < 0)       /* modified 1987/07/22 R. Dhesi */
  945. X                printf("#define Mch_sgc 1\n");
  946. X        }
  947. END_OF_FILE
  948. if test 2812 -ne `wc -c <'mch_defines.c'`; then
  949.     echo shar: \"'mch_defines.c'\" unpacked with wrong size!
  950. fi
  951. # end of 'mch_defines.c'
  952. fi
  953. echo shar: End of shell archive.
  954. exit 0
  955.